library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
library work;
use work.config_01.all;

entity bissc_rw is
port (
	clk            : in std_logic;
	sclk           : in std_logic;
	position_valid : in std_logic;
	position       : in std_logic_vector((position_width - 1) downto 0);
	zero_bias      : in std_logic_vector((position_width - 1) downto 0);
	sda            : out std_logic;
	rdc_trigger    : out std_logic);
end bissc_rw;

architecture bissc_rw_arc of bissc_rw is
signal sTX_State       : integer range 0 to 63;
signal sSCLK_buffer1   : std_logic_vector(1 downto 0);
signal sSCLK_buffer2   : std_logic_vector(3 downto 0);
signal sTX_buffer      : std_logic_vector((bissc_encoder_width - 1) downto 0);--include: [23bit: position], [2bit: Error+Warning]
signal sCNT_clk        : std_logic_vector(11 downto 0);

--about crc
constant polynomial  : std_logic_vector(6 downto 0) := "1000011";--x^6 + x + 1 (0x43)
signal   sCRC_buffer : std_logic_vector(6 downto 0);

begin
--------------------------------------------------------------------------------------
--sample sclk @ clk's rising edge
P1 : process(clk, sclk)
begin
if rising_edge(clk) then
	sSCLK_buffer2(1) <= sSCLK_buffer2(0);
	sSCLK_buffer2(0) <= sSCLK_buffer1(1);
	sSCLK_buffer1(1) <= sSCLK_buffer1(0);
	sSCLK_buffer1(0) <= sclk;
else
	null;
end if;
end process P1;
--------------------------------------------------------------------------------------
--transmission controlling
P2 : process(clk, sCNT_clk, sTX_State, sSCLK_buffer1)
begin
if rising_edge(clk) then
	case sSCLK_buffer1 is
		when "10"=>
			sCNT_clk <= (others=>'0');
		when others =>
            if ((sCNT_clk >= conv_std_logic_vector(SSI_CLK_FREQ*20/1000000, 12))) then
                null;--stop count
            else
                sCNT_clk <= sCNT_clk + conv_std_logic_vector(1, 12);
            end if;
	end case;
	
	if ((sCNT_clk >= conv_std_logic_vector(SSI_CLK_FREQ*20/1000000, 12))) then--reset when time is out @ 20us with MHz clock
		SDA         <= '1';--data line is high in idle state
		sTX_State   <= 0;
		rdc_trigger <= '0';--don't trigger rdc starting
	else
		case sTX_State is
			when 0 =>--wait to transmit
				if ((sSCLK_buffer1 = "01")) then--if ((sSCLK_buffer2 = "00") and (sSCLK_buffer1 = "01")) then--1st rising edge
--                    sTX_buffer((bissc_encoder_width - 1) downto 2) <= position;--update transmit buffer
--					sTX_buffer(1) <= position_valid;
--					sTX_buffer(0) <= '1';--no warning bit, this bit is as reserved
					rdc_trigger   <= '1';--trigger rdc starting
					sTX_State <= sTX_State + 1;--go to next state
				else
					rdc_trigger   <= '0';--don't trigger rdc starting
				end if;
			
			when 1 =>--Ack
				if ((sSCLK_buffer1 = "01")) then--if ((sSCLK_buffer2 = "00") and (sSCLK_buffer1 = "01")) then--2nd rising edge
					SDA       <= '0';
                    sTX_State <= sTX_State + 1;--go to next state
				else
					null;  
				end if;
			when 2 =>--Start
				if ((sSCLK_buffer1 = "01")) then--if ((sSCLK_buffer2 = "00") and (sSCLK_buffer1 = "01")) then--3rd rising edge
                    sTX_buffer((bissc_encoder_width - 1) downto 2) <= position;--update transmit buffer
					sTX_buffer(1) <= position_valid;
					sTX_buffer(0) <= '1';--no warning bit, this bit is as reserved
					SDA       <= '1';
					sTX_State <= sTX_State + 1;--go to next state
				else
					null;
				end if;
			when 3 =>--CDS
				if ((sSCLK_buffer1 = "01")) then--if ((sSCLK_buffer2 = "00") and (sSCLK_buffer1 = "01")) then--4th rising edge
					sCRC_buffer <= sTX_buffer((bissc_encoder_width - 1) downto ((bissc_encoder_width - 6) - 1));
					SDA         <= '0';
					sTX_State   <= sTX_State + 1;--go to next state
				else
					null;
				end if;
			when 4 to (4 + (bissc_encoder_width - 1)) =>--data transmit
				if ((sSCLK_buffer1 = "01")) then--if ((sSCLK_buffer2 = "00") and (sSCLK_buffer1 = "01")) then--
					
					--begin 'crc calculattion
					if (sCRC_buffer(6) = '0') then
						sCRC_buffer <= sCRC_buffer(5 downto 0) & sTX_buffer((bissc_encoder_width - 7) - 1);
					else
						sCRC_buffer <= (sCRC_buffer(5 downto 0) XOR polynomial(5 downto 0)) & sTX_buffer((bissc_encoder_width - 7) - 1);
					end if;
					--end 'crc calculation
					
					SDA        <= sTX_buffer(bissc_encoder_width - 1);
					sTX_buffer <= sTX_buffer((bissc_encoder_width - 2) downto 0) & '0';
					sTX_State  <= sTX_State + 1;--go to next state
					
				else
					null;
				end if;
			when (4 + bissc_encoder_width) =>--crc and stop-bit transmit// to (4 + bissc_encoder_width + 6)
				if ((sSCLK_buffer1 = "01")) then--if ((sSCLK_buffer2 = "00") and (sSCLK_buffer1 = "01")) then--
					SDA <= not sCRC_buffer(6);--biss c requires inverted crc
					sCRC_buffer(6 downto 1) <= sCRC_buffer(5 downto 1) & '1';--'1' is for stop-bit after inverted
--					sTX_State <= sTX_State + 1;--go to next state
				else
					null;
				end if;
--			when (4 + bissc_encoder_width + 7) =>--idle
--                SDA       <= '1';--data line is high in idle state
--                sTX_State <= 0;
			
			when others => null;
		end case;
	end if;
else
	null;
end if;
end process P2;
--------------------------------------------------------------------------------------
end bissc_rw_arc;